#include "EtgRecUnAlmacenamiento.h"
#include "../../../tests/Persona.h"

EtgRecUnAlmacenamiento::EtgRecUnAlmacenamiento(TipoMemoria tipoMemoria,TipoIndice tipoIndice,/*EstrategiaIndice *indice,*/
				TipoAlmacenamiento tipoAlmacenamiento,TipoEstrategia tipoEstrategia,Almacenamiento **persistencia,
																void* ptr,PrimaryKey *PK){
   
     //Ya hice los new en recurso de almacenamiento que lo invoca a este  
     if (tipoIndice==HASH)
     	this->indice=(EstrategiaIndice*) new IndiceHashExtensible(PK); 
     else
        this->indice=(EstrategiaIndice*) new IndiceArbolB(PK);   	
     
     this->tipoIndice = tipoIndice;
     this->PK = PK;
     this->persistencia = persistencia;
     this->tipoAlmacenamiento = tipoAlmacenamiento;
     vector<Dato*> vec;    
     vec.clear();
     this->tipoES=tipoEstrategia;
     switch(this->tipoES){          
          case REGISTROS:
               this->estrategiaAlm = new EstrategiaRegistros(persistencia,tipoAlmacenamiento);
               this->tipoSerializacion = BINARIO;
               break;
          case BLOQUES:
               this->estrategiaAlm = new EstrategiaBloques(persistencia,tipoAlmacenamiento);
               this->tipoSerializacion = BINARIO;
               break;
          case TEXT:
               this->estrategiaAlm = new EstrategiaTexto(persistencia,tipoAlmacenamiento);
               this->tipoSerializacion = TEXTO;               
     }
     this->estrategiaAlm->crear(tipoMemoria,vec,ptr);                                                           
}






void EtgRecUnAlmacenamiento::insertar(Dato *datoNvo){
     if(this->tipoIndice==ARBOL)
         this->insertarArbol(datoNvo);
     else if(this->tipoIndice==HASH)
         this->insertarHashing(datoNvo);     
}

void EtgRecUnAlmacenamiento::insertarArbol(Dato *dato){
     int nro=-1;
     try{
          this->estrategiaAlm->insertar(dato,&nro);
     }
     catch(exception *e){
          throw e;                
     }
     void* datoSerializado=malloc(dato->getTamanio(this->tipoSerializacion));
     dato->serialize(&datoSerializado,this->tipoSerializacion);
    // cout<<"nro es "<<nro;
 
     unsigned int nrob= nro;
     try{
     		
          this->indice->Cargar((char*)datoSerializado,nrob);
     }
     catch(exception *e){
          this->estrategiaAlm->eliminar(dato,nro);               
          throw e;
     }     
     free(datoSerializado);
}

void EtgRecUnAlmacenamiento::insertarHashing(Dato *dato){
     void* datoSerializado=malloc(dato->getTamanio(this->tipoSerializacion));
     
     dato->serialize(&datoSerializado,this->tipoSerializacion);
     this->indice->Cargar((char*)datoSerializado,dato->getTamanio(BINARIO));
     vector<HashChange>* vecAux = ((IndiceHashExtensible*) this->indice)->getModificaciones();   
     
          //Dato *datoA;
     //dato->clone(datoA);
    // this->ejecutarCambios(vecAux, dato,'i');
     /***/
     int bloqueActual, bloqueAnterior, nroReg=-1;
     
     vector<HashChange>:: iterator it;
     
     
     
     for (it=vecAux->begin(); it != vecAux->end(); it++){
     	bloqueAnterior=it->getBloqueAnterior();
        bloqueActual = it->getBloqueActual();
   		if (bloqueAnterior == bloqueActual)
			this->estrategiaAlm->insertar(dato,&bloqueActual);
  		else{
  			//Dato *dAux;
  			//dato->clone(dAux); 
 			buscarHash(dato, &nroReg, bloqueAnterior, it->getClave());	
  			this->estrategiaAlm->eliminar(dato,bloqueAnterior);
 			this->estrategiaAlm->insertar(dato,&bloqueActual);
  		}
     }
     /***/
     vecAux->clear();
     free(datoSerializado);
}

void EtgRecUnAlmacenamiento::buscarHash(Dato *dato, int* nroReg, int nroBloque, unsigned long int clave){

	Compuesto *compuesto;
    Bloque *b;
    RegistroMemoria *regM;
    RegistroDisco *regD;
    //Dato *dAux;
    //dato->clone(dAux);
	if (this->tipoAlmacenamiento==BUFFER)
     	compuesto= this->persistencia[0]->getCompuesto();
     else
     	compuesto= this->persistencia[1]->getCompuesto();
     
	((EstrategiaBloques*) this->estrategiaAlm)->buscar(dato,nroReg,nroBloque,clave,this->tipoSerializacion,this->PK);
    b= (Bloque*)compuesto->getComponenteAt(nroBloque);
    if (this->tipoAlmacenamiento==BUFFER){
    	regM= (RegistroMemoria*)b->getComponenteAt(*nroReg);
    	regM->leer(dato, this->tipoSerializacion);		   
    }
    else{
    	regD= (RegistroDisco*)b->getComponenteAt(*nroReg);
     	regD->leer(dato, this->tipoSerializacion);		   
    }

}

void EtgRecUnAlmacenamiento::ejecutarCambios(vector<HashChange> *vecAux,Dato *datoAux, char op){
     //Dato *datoAux;
  //   datoAux->clone(dato);
  //   datoAux=dato->getNewInstance();
     int bloqueActual, bloqueAnterior, nroReg=-1;
     
     vector<HashChange>:: iterator it;
     for (it=vecAux->begin(); it != vecAux->end(); it++){
     	bloqueAnterior=it->getBloqueAnterior();
        bloqueActual = it->getBloqueActual();
        
     	   
     	switch (op){
     		case 'i': 	if (bloqueAnterior == bloqueActual)
     						this->estrategiaAlm->insertar(datoAux,&bloqueActual);
     				  	else{
     				  		buscarHash(datoAux, &nroReg, bloqueAnterior, it->getClave());	
     				  		this->estrategiaAlm->eliminar(datoAux,bloqueAnterior);
     				  		this->estrategiaAlm->insertar(datoAux,&bloqueActual);
     				  	}
     				  	break;
     		case 'e':	if (bloqueAnterior == bloqueActual)
     						this->estrategiaAlm->eliminar(datoAux,bloqueActual);
     				  	break;
     		case 'm':	buscarHash(datoAux, &nroReg, bloqueAnterior, it->getClave());	
     				  	this->estrategiaAlm->eliminar(datoAux,bloqueAnterior);
     				  	this->estrategiaAlm->insertar(datoAux,&bloqueActual);
     				  	break;
 		}   
     }
}

void EtgRecUnAlmacenamiento::modificar(Dato *datoNvo){
     if(this->tipoIndice==ARBOL)
         this->modificarArbol(datoNvo);
     else if(this->tipoIndice==HASH)
         this->modificarHashing(datoNvo);         
}

void EtgRecUnAlmacenamiento::modificarArbol(Dato *dato){   
	 
   	void* datoSerializadoNuevo=malloc(dato->getTamanio(this->tipoSerializacion));
    dato->serialize(&datoSerializadoNuevo,this->tipoSerializacion);
    int aux;
    int pos=-1;
    char* chrClave = this->PK->GetKey((char*)datoSerializadoNuevo,aux);
    string *strClave = new string(chrClave);
    free(chrClave);
    vector<unsigned int> vec = this->indice->Buscar(*strClave);
    
    if(vec.size()>0){
    	vector<unsigned int>:: iterator it;
    	it=vec.begin();
    	//this->estrategiaAlm->modificar(dato,*it,&pos);
    	//this->indice->Modificar(datoSerializadoSinModificar, char *DatoSerializadoModificado, unsigned int idModificado)
    	this->estrategiaAlm->eliminar(dato,*it);
    	this->indice->Eliminar((char*)datoSerializadoNuevo);
    	this->estrategiaAlm->insertar(dato,&pos);
    	this->indice->Cargar((char*)datoSerializadoNuevo, pos);
    	
    }
    else throw new PrimaryKeyError(KEYNOEXISTE);
}

void EtgRecUnAlmacenamiento::modificarHashing(Dato *dato){
     void* datoSerializadoNuevo=malloc(dato->getTamanio(this->tipoSerializacion));
     dato->serialize(&datoSerializadoNuevo,this->tipoSerializacion);
     void* datoSerializadoViejo=NULL;
     int aux;
     Dato *datoAux;
     char* chrClave = this->PK->GetKey((char*)datoSerializadoNuevo,aux);

     string *strClave = new string(chrClave);
    
     vector<unsigned int> vec = this->indice->Buscar(*strClave);
     if (vec.size() <=0){
     	throw new PrimaryKeyError(KEYNOEXISTE);
     }
     else{
     vector<unsigned int>:: iterator it;
     it=vec.begin();
     
     
     dato->clone(&datoAux);//verrr
     this->estrategiaAlm->leer(datoAux,*it);
     datoSerializadoViejo= malloc(datoAux->getTamanio(this->tipoSerializacion));;
     datoAux->serialize(&datoSerializadoViejo,this->tipoSerializacion);
     
     this->indice->Modificar((char*)datoSerializadoViejo,(char*)datoSerializadoNuevo,dato->getTamanio(BINARIO),datoAux->getTamanio(BINARIO));
    
     
     vector<HashChange>* vecAux = ((IndiceHashExtensible*) this->indice)->getModificaciones();   
     
     //this->ejecutarCambios(vecAux, dato->getNewInstance(), 'm');
     /***/
     
     int bloqueActual, bloqueAnterior, nroReg=-1;
     
     vector<HashChange>:: iterator itm;
     for (itm=vecAux->begin(); itm != vecAux->end(); itm++){
     		bloqueAnterior=itm->getBloqueAnterior();
        	bloqueActual = itm->getBloqueActual();
        	dato->clone(&datoAux);
     		buscarHash(datoAux, &nroReg, bloqueAnterior, itm->getClave());	
     
     		this->estrategiaAlm->eliminar(dato,bloqueAnterior);
   
     		this->estrategiaAlm->insertar(dato,&bloqueActual);
     
     }
     free(datoSerializadoNuevo);
     /***/
     vecAux->clear();
     }
   	free(chrClave);
    delete(strClave);
     delete(datoAux);
     free(datoSerializadoViejo);
      
}
     

void EtgRecUnAlmacenamiento::eliminar(Dato *datoNvo){
     
     if(this->tipoIndice==ARBOL)
         this->eliminarArbol(datoNvo);
     else if(this->tipoIndice==HASH)
         this->eliminarHashing(datoNvo);              
}

void EtgRecUnAlmacenamiento::eliminarArbol(Dato *dato){         
	
	void* datoSerializadoNuevo=malloc(dato->getTamanio(this->tipoSerializacion));
    dato->serialize(&datoSerializadoNuevo,this->tipoSerializacion);
    int aux;
    char* chrClave = this->PK->GetKey((char*)datoSerializadoNuevo,aux);
    string *strClave = new string(chrClave);
    free(chrClave);
    vector<unsigned int> vec = this->indice->Buscar(*strClave);
    if (vec.size()>0){
    	vector<unsigned int>:: iterator it;
    	it=vec.begin();
    	this->estrategiaAlm->eliminar(dato,*it);
    	this->indice->Eliminar((char*)datoSerializadoNuevo);
    }
    else throw PrimaryKeyError(KEYNOEXISTE);
}

void EtgRecUnAlmacenamiento::eliminarHashing(Dato *dato){
	
     void* datoSerializado= malloc(dato->getTamanio(this->tipoSerializacion));
     dato->serialize(&datoSerializado,this->tipoSerializacion);
     this->indice->Eliminar((char*)datoSerializado);
     vector<HashChange>* vecAux = ((IndiceHashExtensible*) this->indice)->getModificaciones();   
    
     int bloqueActual, bloqueAnterior;
     
     vector<HashChange>:: iterator it;
     for (it=vecAux->begin(); it != vecAux->end(); it++){
     	bloqueAnterior=it->getBloqueAnterior();
        bloqueActual = it->getBloqueActual();		
     		
     	if (bloqueAnterior == bloqueActual){
     		this->estrategiaAlm->eliminar(dato,bloqueActual);
     		this->indice->Eliminar((char*)datoSerializado);
     	}
     		
     }
     /**/
     vecAux->clear();
     free(datoSerializado);    
}


void EtgRecUnAlmacenamiento::leer(Dato *dato){
	void* datoSerializadoNuevo= malloc(dato->getTamanio(this->tipoSerializacion));
	
	
    dato->serialize(&datoSerializadoNuevo,this->tipoSerializacion);
    int aux;
    char* chrClave = this->PK->GetKey((char*)datoSerializadoNuevo,aux);
    string *strClave = new string(chrClave);
    free(chrClave);
    vector<unsigned int> vec = this->indice->Buscar(*strClave);
    if (vec.size() >0){
	    vector<unsigned int>:: iterator it;
    	it=vec.begin();
    	
    //	if (this->tipoES==BLOQUES)
    		this->estrategiaAlm->leer(dato,*it);         
    //	else
    	//	this->estrategiaAlm->leer(dato);
    }
    else throw new PrimaryKeyError(KEYNOEXISTE);
    free(datoSerializadoNuevo);
}
/*
void EtgRecUnAlmacenamiento::listar(Dato *dini, Dato *dfin, vector<Dato*> lista){
	//TODO
}*/
